// Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Runtime.InteropServices;
using System.Windows.Media.Media3D;

namespace Microsoft.WindowsAPICodePack.DirectX.DirectXUtilities
{
    [StructLayout(LayoutKind.Sequential)]
    public struct Matrix4F
    {
        public float _11, _12, _13, _14;
        public float _21, _22, _23, _24;
        public float _31, _32, _33, _34;
        public float _41, _42, _43, _44;

        #region public Matrix4F(float[] matrix)
        public Matrix4F(params float[] matrix)
        {
            _11 = matrix[  0];
            _12 = matrix[  1];
            _13 = matrix[  2];
            _14 = matrix[  3];

            _21 = matrix[  4];
            _22 = matrix[  5];
            _23 = matrix[  6];
            _24 = matrix[  7];

            _31 = matrix[  8];
            _32 = matrix[  9];
            _33 = matrix[ 10];
            _34 = matrix[ 11];

            _41 = matrix[ 12];
            _42 = matrix[ 13];
            _43 = matrix[ 14];
            _44 = matrix[ 15];
        } 
        #endregion

        #region public Matrix4F(Matrix3D wpfMatrix)
        public Matrix4F(Matrix3D wpfMatrix)
        {
            _11 = (float)wpfMatrix.M11;
            _12 = (float)wpfMatrix.M12;
            _13 = (float)wpfMatrix.M13;
            _14 = (float)wpfMatrix.M14;

            _21 = (float)wpfMatrix.M21;
            _22 = (float)wpfMatrix.M22;
            _23 = (float)wpfMatrix.M23;
            _24 = (float)wpfMatrix.M24;

            _31 = (float)wpfMatrix.M31;
            _32 = (float)wpfMatrix.M32;
            _33 = (float)wpfMatrix.M33;
            _34 = (float)wpfMatrix.M34;

            _41 = (float)wpfMatrix.OffsetX;
            _42 = (float)wpfMatrix.OffsetY;
            _43 = (float)wpfMatrix.OffsetZ;
            _44 = (float)wpfMatrix.M44;
        } 
        #endregion

        #region float[] ToArray()
        public float[] ToArray()
        {
            return new float[]
            {
                _11, _12, _13, _14,
                _21, _22, _23, _24,
                _31, _32, _33, _34,
                _41, _42, _43, _44
            };
        } 
        #endregion

        #region MatrixIdentity()
        public static Matrix4F MatrixIdentity()
        {
            Matrix4F matrix = new Matrix4F();
            matrix._12 = matrix._13 = matrix._14 =
            matrix._21 = matrix._23 = matrix._24 =
            matrix._31 = matrix._32 = matrix._34 =
            matrix._41 = matrix._42 = matrix._43 = 0.0F;
            matrix._11 = matrix._22 = matrix._33 = matrix._44 = 1.0f;
            return matrix;
        } 
        #endregion

        #region operator *
        public static Matrix4F operator *(Matrix4F a, Matrix4F b)
        {
            return new Matrix4F(
                a._11 * b._11 + a._12 * b._21 + a._13 * b._31 + a._14 * b._41,
                a._11 * b._12 + a._12 * b._22 + a._13 * b._32 + a._14 * b._42,
                a._11 * b._13 + a._12 * b._23 + a._13 * b._33 + a._14 * b._43,
                a._11 * b._14 + a._12 * b._24 + a._13 * b._34 + a._14 * b._44,

                a._21 * b._11 + a._22 * b._21 + a._23 * b._31 + a._24 * b._41,
                a._21 * b._12 + a._22 * b._22 + a._23 * b._32 + a._24 * b._42,
                a._21 * b._13 + a._22 * b._23 + a._23 * b._33 + a._24 * b._43,
                a._21 * b._14 + a._22 * b._24 + a._23 * b._34 + a._24 * b._44,

                a._31 * b._11 + a._32 * b._21 + a._33 * b._31 + a._34 * b._41,
                a._31 * b._12 + a._32 * b._22 + a._33 * b._32 + a._34 * b._42,
                a._31 * b._13 + a._32 * b._23 + a._33 * b._33 + a._34 * b._43,
                a._31 * b._14 + a._32 * b._24 + a._33 * b._34 + a._34 * b._44,

                a._41 * b._11 + a._42 * b._21 + a._43 * b._31 + a._44 * b._41,
                a._41 * b._12 + a._42 * b._22 + a._43 * b._32 + a._44 * b._42,
                a._41 * b._13 + a._42 * b._23 + a._43 * b._33 + a._44 * b._43,
                a._41 * b._14 + a._42 * b._24 + a._43 * b._34 + a._44 * b._44
                );
        }

        public static Vector4F operator *(Matrix4F a, Vector4F b)
        {
            return new Vector4F(
                //a._11 * b.x + a._21 * b.y + a._31 * b.z + a._41 * b.w,
                //a._12 * b.x + a._22 * b.y + a._32 * b.z + a._42 * b.w,
                //a._13 * b.x + a._23 * b.y + a._33 * b.z + a._43 * b.w,
                //a._14 * b.x + a._24 * b.y + a._34 * b.z + a._44 * b.w
                a._11 * b.x + a._12 * b.y + a._13 * b.z + a._14 * b.w,
                a._21 * b.x + a._22 * b.y + a._23 * b.z + a._24 * b.w,
                a._31 * b.x + a._32 * b.y + a._33 * b.z + a._34 * b.w,
                a._41 * b.x + a._42 * b.y + a._43 * b.z + a._44 * b.w
                );
        }
        #endregion

        #region MatrixScale
        public static Matrix4F MatrixScale(float x, float y, float z)
        {
            return new Matrix4F(
                x, 0, 0, 0,
                0, y, 0, 0,
                0, 0, z, 0,
                0, 0, 0, 1
                );
        } 
        #endregion

        #region MatrixTranslate
        public static Matrix4F MatrixTranslate(float x, float y, float z)
        {
            return new Matrix4F(
                1, 0, 0, 0,
                0, 1, 0, 0,
                0, 0, 1, 0,
                x, y, z, 1
                );
        }
        #endregion

        #region MatrixRotationX
        public static Matrix4F MatrixRotationX(float angle)
        {
            float sin = (float)Math.Sin(angle);
            float cos = (float)Math.Cos(angle);
            return new Matrix4F(
                1, 0, 0, 0,
                0, cos, sin, 0,
                0, -sin, cos, 0,
                0, 0, 0, 1
                );
        }
        #endregion

        #region MatrixRotationY
        public static Matrix4F MatrixRotationY(float angle)
        {
            float sin = (float)Math.Sin(angle);
            float cos = (float)Math.Cos(angle);
            return new Matrix4F(
                cos, 0, -sin, 0,
                0, 1, 0, 0,
                sin, 0, cos, 0,
                0, 0, 0, 1
                );
        }
        #endregion

        #region MatrixRotationZ
        public static Matrix4F MatrixRotationZ(float angle)
        {
            float sin = (float)Math.Sin(angle);
            float cos = (float)Math.Cos(angle);
            return new Matrix4F(
                cos, sin, 0, 0,
                -sin, cos, 0, 0,
                0, 0, 1, 0,
                0, 0, 0, 1
                );
        }
        #endregion
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct Matrix4D
    {
        public double _11, _12, _13, _14;
        public double _21, _22, _23, _24;
        public double _31, _32, _33, _34;
        public double _41, _42, _43, _44;

        #region public Matrix4D(double[] matrix)
        public Matrix4D(params double[] matrix)
        {
            _11 = matrix[0];
            _12 = matrix[1];
            _13 = matrix[2];
            _14 = matrix[3];

            _21 = matrix[4];
            _22 = matrix[5];
            _23 = matrix[6];
            _24 = matrix[7];

            _31 = matrix[8];
            _32 = matrix[9];
            _33 = matrix[10];
            _34 = matrix[11];

            _41 = matrix[12];
            _42 = matrix[13];
            _43 = matrix[14];
            _44 = matrix[15];
        }
        #endregion

        #region public Matrix4D(Matrix3D wpfMatrix)
        public Matrix4D(Matrix3D wpfMatrix)
        {
            _11 = wpfMatrix.M11;
            _12 = wpfMatrix.M12;
            _13 = wpfMatrix.M13;
            _14 = wpfMatrix.M14;

            _21 = wpfMatrix.M21;
            _22 = wpfMatrix.M22;
            _23 = wpfMatrix.M23;
            _24 = wpfMatrix.M24;

            _31 = wpfMatrix.M31;
            _32 = wpfMatrix.M32;
            _33 = wpfMatrix.M33;
            _34 = wpfMatrix.M34;

            _41 = wpfMatrix.OffsetX;
            _42 = wpfMatrix.OffsetY;
            _43 = wpfMatrix.OffsetZ;
            _44 = wpfMatrix.M44;
        }
        #endregion

        #region float[] ToArray()
        public float[] ToArray()
        {
            return new float[]
            {
                (float)_11, (float)_12, (float)_13, (float)_14,
                (float)_21, (float)_22, (float)_23, (float)_24,
                (float)_31, (float)_32, (float)_33, (float)_34,
                (float)_41, (float)_42, (float)_43, (float)_44
            };
        }
        #endregion

        #region MatrixIdentity()
        public static Matrix4D MatrixIdentity()
        {
            Matrix4D matrix = new Matrix4D();
            matrix._12 = matrix._13 = matrix._14 =
            matrix._21 = matrix._23 = matrix._24 =
            matrix._31 = matrix._32 = matrix._34 =
            matrix._41 = matrix._42 = matrix._43 = 0.0F;
            matrix._11 = matrix._22 = matrix._33 = matrix._44 = 1.0f;
            return matrix;
        }
        #endregion

        #region operator *
        public static Matrix4D operator *(Matrix4D a, Matrix4D b)
        {
            return new Matrix4D(
                a._11 * b._11 + a._12 * b._21 + a._13 * b._31 + a._14 * b._41,
                a._11 * b._12 + a._12 * b._22 + a._13 * b._32 + a._14 * b._42,
                a._11 * b._13 + a._12 * b._23 + a._13 * b._33 + a._14 * b._43,
                a._11 * b._14 + a._12 * b._24 + a._13 * b._34 + a._14 * b._44,

                a._21 * b._11 + a._22 * b._21 + a._23 * b._31 + a._24 * b._41,
                a._21 * b._12 + a._22 * b._22 + a._23 * b._32 + a._24 * b._42,
                a._21 * b._13 + a._22 * b._23 + a._23 * b._33 + a._24 * b._43,
                a._21 * b._14 + a._22 * b._24 + a._23 * b._34 + a._24 * b._44,

                a._31 * b._11 + a._32 * b._21 + a._33 * b._31 + a._34 * b._41,
                a._31 * b._12 + a._32 * b._22 + a._33 * b._32 + a._34 * b._42,
                a._31 * b._13 + a._32 * b._23 + a._33 * b._33 + a._34 * b._43,
                a._31 * b._14 + a._32 * b._24 + a._33 * b._34 + a._34 * b._44,

                a._41 * b._11 + a._42 * b._21 + a._43 * b._31 + a._44 * b._41,
                a._41 * b._12 + a._42 * b._22 + a._43 * b._32 + a._44 * b._42,
                a._41 * b._13 + a._42 * b._23 + a._43 * b._33 + a._44 * b._43,
                a._41 * b._14 + a._42 * b._24 + a._43 * b._34 + a._44 * b._44
                );
        }
        #endregion

        #region MatrixScale
        public static Matrix4D MatrixScale(double x, double y, double z)
        {
            return new Matrix4D(
                x, 0, 0, 0,
                0, y, 0, 0,
                0, 0, z, 0,
                0, 0, 0, 1
                );
        }
        #endregion

        #region MatrixTranslate
        public static Matrix4D MatrixTranslate(double x, double y, double z)
        {
            return new Matrix4D(
                1, 0, 0, 0,
                0, 1, 0, 0,
                0, 0, 1, 0,
                x, y, z, 1
                );
        }
        #endregion

        #region MatrixRotationX
        public static Matrix4D MatrixRotationX(double angle)
        {
            double sin = (double)Math.Sin(angle);
            double cos = (double)Math.Cos(angle);
            return new Matrix4D(
                1, 0, 0, 0,
                0, cos, sin, 0,
                0, -sin, cos, 0,
                0, 0, 0, 1
                );
        }
        #endregion

        #region MatrixRotationY
        public static Matrix4D MatrixRotationY(double angle)
        {
            double sin = (double)Math.Sin(angle);
            double cos = (double)Math.Cos(angle);
            return new Matrix4D(
                cos, 0, -sin, 0,
                0, 1, 0, 0,
                sin, 0, cos, 0,
                0, 0, 0, 1
                );
        }
        #endregion

        #region MatrixRotationZ
        public static Matrix4D MatrixRotationZ(double angle)
        {
            double sin = (double)Math.Sin(angle);
            double cos = (double)Math.Cos(angle);
            return new Matrix4D(
                cos, sin, 0, 0,
                -sin, cos, 0, 0,
                0, 0, 1, 0,
                0, 0, 0, 1
                );
        }
        #endregion
    }
}
